-module(tk_config).
-include("common.hrl").
-export([preload_config/0, reload_config/1]).

%% ====================================================================
%% Internal functions
%% ====================================================================

%% @doc 预加载配置
preload_config() ->
	RootDir = util:root_dir(),
	OutDir = filename:join([RootDir, "ebin"]),
	lists:foreach(fun(Data) ->
		do_compile_config(RootDir, OutDir, Data)
	              end, preload_config_list()).

reload_config(ConfigMod) ->
	RootDir = util:root_dir(),
	OutDir = filename:join([RootDir, "ebin"]),
	case lists:keyfind(ConfigMod, 2, preload_config_list()) of
		?FALSE ->
			?ERR("this config is new，please write in preload_config_list()");
		Data ->
			do_compile_config(RootDir,OutDir,Data),
			c:l(ConfigMod)
	end.

%%================================LOCAL FUNCTION========================================
do_compile_config(RootDir, OutDir, Data) ->
	case Data of
		{ConfigPath, ModuleAtom, Type} ->
			SrcFileFullName = filename:join([RootDir, ConfigPath]),
			case checkNeedReload(SrcFileFullName,ModuleAtom,OutDir) of
				?FALSE -> ok;
				MD5 ->
					io:format("load config ~p\n",[ModuleAtom]),
					config2erl:beam(SrcFileFullName, ModuleAtom, OutDir, Type, original,MD5),
					c:l(ModuleAtom)
			end;
		{ConfigPath, ModuleAtom, Type, TransformFun} ->
			SrcFileFullName = filename:join([RootDir, ConfigPath]),
			case checkNeedReload(SrcFileFullName,ModuleAtom,OutDir) of
				?FALSE -> ok;
				MD5 ->
					io:format("load config ~p\n",[ModuleAtom]),
					config2erl:beam(SrcFileFullName, ModuleAtom, OutDir, Type, TransformFun,MD5),
					c:l(ModuleAtom)
			end;
		Fun when is_function(Fun, 1) ->
			Fun(OutDir);
		Fun when is_function(Fun, 0) ->
			Fun();
		_ ->
			?ERR("do_compile_config Data = ~p", [Data])
	end.

%%检测MD5是否有变化，是否需要重新编译
%%return false|Md5::binary()
checkNeedReload(SrcFileFullName, ModuleAtomList, OutDir) ->
	try
		M = erlang:md5_init(),
		Bin = case file:read_file(SrcFileFullName) of
			      {ok, Bin0} -> Bin0;
			      {error, Reason} -> throw({read, Reason})
		      end,
		M1 = erlang:md5_update(M, Bin),
		M2 = erlang:md5_final(M1),
		IsNeedCompile = case is_list(ModuleAtomList) of
			                ?TRUE -> lists:any(fun(ModuleAtom) -> checkSingleNeedReload(M2,ModuleAtom,OutDir) end,ModuleAtomList);
			                _ -> checkSingleNeedReload(M2,ModuleAtomList,OutDir)
		                end,
		case IsNeedCompile of
			?TRUE ->
				%%返回新MD5，执行编译
				M2;
			_ -> ?FALSE
		end
	catch
		_:Why ->
			io:format("checkNeedReload File=~s error Why=~p~n", [SrcFileFullName, Why]),
			?FALSE
	end.

checkSingleNeedReload(MD5, ModuleAtom,OutDir) ->
	%%OutDir里面是否有该文件
	OutFile = filename:join([OutDir, erlang:atom_to_list(ModuleAtom) ++ ".beam"]),
	IsNeedCompile = case filelib:is_file(OutFile) of
		                ?TRUE ->
			                %%beam文件里面是否有get_md5()函数
			                ExportsList = ModuleAtom:module_info(exports),
			                case lists:member({get_md5, 0}, ExportsList) of
				                ?TRUE ->
					                %%md5值是否一致
					                OldMd5 = ModuleAtom:get_md5(),
					                OldMd5 =/= MD5;
				                _ -> ?TRUE
			                end;
		                _ -> ?TRUE
	                end,
%%	io:format("debug  Module=~p IsNeedCompile=~p~s~n", [ModuleAtom, IsNeedCompile,?IF(IsNeedCompile,"*****","")]),
	IsNeedCompile.

%%================================配置列表========================================
%%列表中元素可以是
%%{ConfigPath, ModuleName, OutputType, TransformFun} %%TransformFun 默认为original 不变 这个参数可以省略
%% fun/1
%% fun/0
preload_config_list() ->
	[
		%%服务器配置
		{"setting/setting.config", data_setting, key_value},

		{"config/module/data_common.config",data_common,key_value},
		{"config/module/data_station.config",data_station,key_value},
		{"config/module/data_piece.config",data_piece,key_value},
		{"config/module/data_battle.config",data_battle,key_value},
		{"config/module/data_chat.config",data_chat,key_value},
		{"config/module/data_name.config",data_name,key_value},
		{"config/module/data_room_name.config",data_room_name,key_value},
		{"config/module/data_head.config",data_head,key_value},
		{"config/module/data_update_sql.config",data_update_sql,key_value}
	].